package com.xuecheng.media.service.impl;

import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.vod.model.v20170321.GetPlayInfoResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xuecheng.api.media.model.dto.MediaDTO;
import com.xuecheng.api.media.model.qo.QueryMediaModel;
import com.xuecheng.common.domain.code.CommonErrorCode;
import com.xuecheng.common.domain.page.PageRequestParams;
import com.xuecheng.common.domain.page.PageVO;
import com.xuecheng.common.domain.response.RestResponse;
import com.xuecheng.common.enums.common.AuditEnum;
import com.xuecheng.common.enums.common.CommonEnum;
import com.xuecheng.common.exception.ExceptionCast;
import com.xuecheng.common.util.StringUtil;
import com.xuecheng.media.common.constant.MediaErrorCode;
import com.xuecheng.media.common.utils.AliyunVODUtil;
import com.xuecheng.media.controller.TMediaAuditController;
import com.xuecheng.media.convert.MediaConvert;
import com.xuecheng.media.entity.Media;
import com.xuecheng.media.mapper.MediaMapper;
import com.xuecheng.media.service.MediaService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.util.Collections;
import java.util.List;

/**
 * 媒资内容管理
 *
 * @author lily
 * @date 2021/12/15
 */
@Slf4j
@Service
public class MediaServiceImpl extends ServiceImpl<MediaMapper, Media> implements MediaService {

    //# 阿里云基础服务
    //aliyun.region = cn-shanghai
    //aliyun.accessKeyId = LTAI5tKeQM26TvqyNucxDBFZ
    //aliyun.accessKeySecret = LjVYXkp2zD3yjpHe631epGRgzzESAG
    @Value("${aliyun.region}")
    private String region;
    @Value("${aliyun.accessKeyId}")
    private String accessKeyId;
    @Value("${aliyun.accessKeySecret}")
    private String accessKeySecret;

    /**
     * 根据媒资名称模糊进行查询，根据媒资的类型进行查询
     *
     * @param pageParams 分页数据
     * @param model      查询数据
     * @param companyId  公司id
     * @return
     * @author Lily
     * @date 2021/12/15 16:07
     * @paramType [java.lang.String, java.lang.String]
     * @description 业务分析：
     * 1.关键数据（判断数据的合法性）
     * 2.构建分页对象
     * 3.获取查询结果
     * 4.返回查询结果
     */
    @Override
    public PageVO queryMediaList(PageRequestParams pageParams, QueryMediaModel model, Long companyId) {

        // 0.（判断数据的合法性）
        // 参数可以不填

        // 1.判断业务数据
        // 公司id是否为空？不需要判断，查询的时候根据公司id查询

        // 2.构建分页对象
        if (pageParams.getPageNo() < 1) {
            pageParams.setPageNo(PageRequestParams.DEFAULT_PAGE_NUM);
        }
        if (pageParams.getPageSize() < 1) {
            pageParams.setPageSize(PageRequestParams.DEFAULT_PAGE_SIZE);
        }
        Page<Media> mediaPage = new Page<>(pageParams.getPageNo(), pageParams.getPageSize());

        // 3.获取查询结果
        LambdaQueryWrapper<Media> queryWrapper = new LambdaQueryWrapper<>();

        // 模糊查询媒资名称，如果传参
//        if (!ObjectUtils.isEmpty(model.getMediaName())) {
//            queryWrapper.like(Media::getFilename, model.getMediaName());
//        }
        queryWrapper.like(StringUtils.isNotBlank(model.getMediaName()), Media::getFilename, model.getMediaName());

        // 判断媒资的类型，如果传参
//        if (!ObjectUtils.isEmpty(model.getType())) {
//            queryWrapper.eq(Media::getType, model.getType());
//        }
        queryWrapper.eq(StringUtil.isNotBlank(model.getType()), Media::getType, model.getType());

        // TODO 判断公司的id，如果为运营平台，则跳过
        if (!TMediaAuditController.OPERATION_FLAG.equals(companyId)) {
            queryWrapper.eq(Media::getCompanyId, companyId);
        }

        // TODO 判断是否逻辑删除，要获取String型
        queryWrapper.eq(Media::getStatus, CommonEnum.USING_FLAG.getCode());

        // TODO 分页查询
        Page<Media> page = this.page(mediaPage, queryWrapper);

        // 获取所有查询到的数据
        List<Media> records = page.getRecords();

        // 判断是否为空，不为空则转为 dto
        List<MediaDTO> mediaDTOS = Collections.emptyList();
        if (!ObjectUtils.isEmpty(records)) {
            mediaDTOS = MediaConvert.INSTANCE.entitys2dtos(records);
        }

        // 4.将查询结果封装PageVO并返回
        PageVO<MediaDTO> pageVO = new PageVO<>(mediaDTOS, mediaPage.getTotal(), mediaPage.getCurrent(), mediaPage.getSize());
        return pageVO;
    }



    @Override
    /**
     * @author Lily
     * @date 2021/12/19 21:12
     * @paramType [com.xuecheng.api.media.model.dto.MediaDTO]
     * @param dto
     * @return com.xuecheng.api.media.model.dto.MediaDTO
     * @description 媒资信息 服务实现类
     * 业务分析：
     *   1.判断关键
     *       companyid  filename  fileid(videoId)
     *   2.给信息数据赋值默认值
     *       auditStatus：未审核
     *   3.保存信息
     *   4.将数据库最新数据返回
     */
    public MediaDTO createMedia(MediaDTO dto) {

        //1.判断关键
        //    companyid  filename  fileid(videoId)
        if (ObjectUtils.isEmpty(dto.getCompanyId()) ||
                ObjectUtils.isEmpty(dto.getFilename()) ||
                ObjectUtils.isEmpty(dto.getFileId())
        ) {
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }

        //2.给信息数据赋值默认值
        //    auditStatus：未审核
        dto.setAuditStatus(AuditEnum.AUDIT_UNPAST_STATUS.getCode());

        //3.保存信息
        Media media = MediaConvert.INSTANCE.dto2entity(dto);
        boolean save = this.save(media);

        if (!save){
            ExceptionCast.cast(MediaErrorCode.E_140001);
        }

        //4.将数据库最新数据返回
        Media po = this.getById(media.getId());
        MediaDTO mediaDTO = MediaConvert.INSTANCE.entity2dto(po);
        return mediaDTO;
    }


    /**
     * @author Lily
     * @date 2021/12/19 21:50
     * @paramType [com.xuecheng.common.domain.page.PageRequestParams, com.xuecheng.api.media.model.qo.QueryMediaModel, java.lang.Long]
     * @param params 分页参数，当前页、每页条数
     * @param model 返回的数据
     * @param companyId 公司 id
     * @return com.xuecheng.common.domain.page.PageVO
     * @description 机构分页查询媒资信息
     * 业务分析：
     * 1.判断关键数据
     * 2.判断业务数据
     * 3.获取查询结果
     * 4.返回查询结果
     *
     */
    @Override
    public PageVO queryMedia(PageRequestParams params, QueryMediaModel model, Long companyId) {

        //1.判断关键数据
        //无需判断公司id，因为查询的时候，根据公司id查的

        //2.判断业务数据
        if (params.getPageNo() < 1){
            params.setPageNo(PageRequestParams.DEFAULT_PAGE_NUM);
        }
        if (params.getPageSize() < 1){
            params.setPageSize(PageRequestParams.DEFAULT_PAGE_SIZE);
        }

        //3.获取查询结果
        //创建分页对象
        Page<Media> mediaPage = new Page<>(params.getPageNo(), params.getPageSize());
        //构件查询条件
        LambdaQueryWrapper<Media> queryWrapper = new LambdaQueryWrapper<>();
        //模糊查询
        queryWrapper.like(StringUtils.isNotBlank(model.getMediaName()), Media::getFilename, model.getMediaName());
        //这里是等于
        queryWrapper.eq(StringUtils.isNotBlank(model.getType()), Media::getType, model.getType());

        //TODO 当用户绑定时，获取的查询结果只能为审核通过的，加上一个判断条件，如果传参了，则会执行这个方法
        queryWrapper.eq(StringUtils.isNotBlank(model.getAuditStatus()), Media::getAuditStatus, AuditEnum.AUDIT_PASTED_STATUS.getCode());

        //TODO 如果是平台查询，不需要传递公司id，因此这里需要判断一下
        queryWrapper.eq(!(ObjectUtils.isEmpty(companyId)), Media::getCompanyId, companyId);
        //判断是否删除，这里是，枚举类，需要获取里面的字段
        queryWrapper.eq(Media::getStatus, CommonEnum.USING_FLAG.getCode());
        Page<Media> po = this.page(mediaPage, queryWrapper);
        //获取所有数据
        List<Media> records = po.getRecords();
        //封装为pagevo数据
        List<MediaDTO> mediaDTOS = Collections.emptyList();
        if (!ObjectUtils.isEmpty(records)){
            mediaDTOS = MediaConvert.INSTANCE.entitys2dtos(records);
        }
        //4.返回查询结果
        PageVO<MediaDTO> pageVO = new PageVO<>(mediaDTOS, po.getTotal(), po.getCurrent(), po.getSize());
        return pageVO;
    }


    /**
     * @author Lily
     * @date 2021/12/20 19:33
     * @paramType [java.lang.Long, java.lang.Long]
     * @param mediaId 媒资id
     * @param companyId 公司id
     * @return java.lang.String
     * @description 获取机构或平台预览课程内容
     *
     * 业务分析：
     * 1.判断业务数据
     *   媒资id是否为空
     * 2.根据媒资id获得媒资信息
     * 3.如果公司id不为空，则为平台查询，否则查询公司id
     * 4.返回媒资的资源地址
     */
    @Override
    public String getVODUrl(Long mediaId, Long companyId) {
        // 1.判断业务数据
        //   媒资id是否为空
        if (ObjectUtils.isEmpty(mediaId)){
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }

        // 2.根据媒资id获得媒资信息
        Media media = this.getById(mediaId);
        if (ObjectUtils.isEmpty(media)){
            ExceptionCast.cast(CommonErrorCode.E_100104);
        }

        // 3.如果公司id不为空，且判断是否为该公司的媒资
        if (!(ObjectUtils.isEmpty(companyId))){
            if (!(ObjectUtils.nullSafeEquals(media.getCompanyId(), companyId))){
                ExceptionCast.cast(CommonErrorCode.E_100108);
            }
        }

        // 4.返回媒资的资源地址
        String playUrl = this.getPlayUrl(media.getFileId());
        return playUrl;
    }

    private String getPlayUrl(String fileId) {
        String playUrl = "";
        try {
            DefaultAcsClient client = AliyunVODUtil.initVodClient(region, accessKeyId, accessKeySecret);
            GetPlayInfoResponse response = AliyunVODUtil.getPlayInfo(client, fileId);
            List<GetPlayInfoResponse.PlayInfo> playInfoList = response.getPlayInfoList();
            if (!(ObjectUtils.isEmpty(playInfoList))){
                GetPlayInfoResponse.PlayInfo playInfo = playInfoList.get(0);
                playUrl = playInfo.getPlayURL();
            }
        } catch (Exception e) {
            ExceptionCast.cast(MediaErrorCode.E_140014);
        }
        return playUrl;
    }
    /**
     * 逻辑删除媒资信息
     *
     * @param mediaId 媒资Id
     * @param mediaId 公司id
     * @author Lily
     * @date 2021/12/15 19:55
     * @paramType [java.lang.Long]
     * @description 业务分析：
     * 1.判断关键数据
     * 媒资id
     * 2.判断业务数据
     * id是否存在
     * 是否是一家公司
     * 是否删除
     * 3.修改删除的status值
     */
    @Transactional
    @Override
    public void removeMedia(Long mediaId, Long companyId) {

        // 1.判断关键数据
        //   媒资id是否为空
        if (ObjectUtils.isEmpty(mediaId)) {
            ExceptionCast.cast(CommonErrorCode.E_110006);
        }

        // 2.判断业务数据
        LambdaQueryWrapper<Media> queryWrapper = new LambdaQueryWrapper<>();

        //   id是否存在
        queryWrapper.eq(Media::getId, mediaId);

        //   是否是一家公司
        queryWrapper.eq(Media::getCompanyId, companyId);

        //   TODO 是否删除，要获取String型
        queryWrapper.eq(Media::getStatus, CommonEnum.USING_FLAG.getCode());

        // 判断是否有数据
        int count = this.count(queryWrapper);
        if (count < 1) {
            ExceptionCast.cast(CommonErrorCode.E_100104);
        }

        // 3.修改删除的status值
        LambdaUpdateWrapper<Media> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(Media::getStatus, CommonEnum.DELETE_FLAG.getCode());
        updateWrapper.eq(Media::getId, mediaId);
        boolean updateResult = this.update(updateWrapper);

        // 判断是否删除成功
        if (!updateResult) {
            ExceptionCast.cast(CommonErrorCode.E_110009);
        }
    }


    /**
     * @author Lily
     * @date 2021/12/20 22:22
     * @paramType [java.lang.Long]
     * @param mediaId
     * @return com.xuecheng.common.domain.response.RestResponse
     * @description 根据id查询媒资信息-远端服务调用
     * 业务分析：
     * PS：由于是学成内部微服务调用，此功能只需要提供基础数据即可，不需要加上业务逻辑判断
     * 如果为了业务的完整性，可以对传入和传出的参数进行判断
     *
     * 1.判断mediaId是否为空
     * 2.查询数据
     * 3.判断数据是否存在
     * 4.如果存在，使用RestResponse来封装返回
     */
    @Override
    public RestResponse getById4Service(Long mediaId) {

        //判断传入数据是否为空
        if (ObjectUtils.isEmpty(mediaId)){
            return RestResponse.validfail(CommonErrorCode.E_100101);
        }

        //判断业务数据
        Media media = this.getById(mediaId);
        if (ObjectUtils.isEmpty(media)){
            return RestResponse.validfail(MediaErrorCode.E_140005);
        }

        //返回数据
        MediaDTO mediaDTO = MediaConvert.INSTANCE.entity2dto(media);
        return RestResponse.success(mediaDTO);
    }
}
